#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#include "socket_udp.h"

int SocketUdpCreateServer(char *pbyLocalIp, int nLocalPort)
{
	struct sockaddr_in server_addr;
	int nSocket = -1;
	int nOpt = 1;

	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(nLocalPort);

	/* ????socket */
	nSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (nSocket == -1)
	{
		perror("SocketUdpCreateServer Create Socket Failed:");
		return -1;
	}

	/*??????*/
	if (setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, &nOpt, sizeof(nOpt)) == -1)
	{
		perror("setsockopt");
		close(nSocket);
		return -1;
	}

	/* ?????? */
	if (bind(nSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
	{
		perror("SocketUdpCreateServer Server Bind Failed:");
		close(nSocket);
		return -1;
	}

	return nSocket;
}

int SocketUdpDestroyServer(int nSocket)
{
	if (nSocket > 0)
	{
		close(nSocket);
	}
	return 0;
}

int SocketUdpRecv(SOCKET_UDP_SECTION_S *pstSection, char *pbyBuf, int nLen)
{
	int nRet = 0;
	struct sockaddr_in remote_addr;
	socklen_t addr_len = sizeof(remote_addr);

	nRet = recvfrom(pstSection->nSocket, pbyBuf, nLen, 0, (struct sockaddr *)&remote_addr, &addr_len);
	if (nRet < 1)
	{
		if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
		{
			printf("SocketUdpRecv recv EINTR,EWOULDBLOCK,EAGAIN\n");
			return 0;
		}
		else
		{
			return -1;
		}
	}

	/*???????IP*/
	strcpy(pstSection->abyRemoteIp, inet_ntoa(remote_addr.sin_addr));
	pstSection->nRemotePort = (int)htons(remote_addr.sin_port);

	return nRet;
}

int SocketUdpSend(SOCKET_UDP_SECTION_S *pstSection, char *pbyBuf, int nLen)
{
	struct sockaddr_in remote_addr;
	socklen_t addr_len = sizeof(remote_addr);

	bzero(&remote_addr, sizeof(remote_addr));
	remote_addr.sin_family = AF_INET;
	remote_addr.sin_addr.s_addr = inet_addr(pstSection->abyRemoteIp);
	remote_addr.sin_port = htons(pstSection->nRemotePort);

	return sendto(pstSection->nSocket, pbyBuf, nLen, 0, (struct sockaddr *)&remote_addr, addr_len);
}
